#include <QPainterPath>
#include <QPainterPathStroker>

#include "connectionitem.h"
#include "plcelement.h"

ConnectionItem::ConnectionItem(PlcElement *startItem, Side startSide,  PlcElement *endItem, Side endSide, QGraphicsItem *parent)
    : QGraphicsLineItem(parent)
    , m_startItem(startItem)
    , m_endItem(endItem)
    , m_startSide(startSide)
    , m_endSide(endSide)
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setPen(QPen(m_color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    updatePosition();
}

// 元素-锚点
ConnectionItem::ConnectionItem(PlcElement *startItem, Side startSide, const QPointF& endAnchorScenePos, QGraphicsItem *parent)
    : QGraphicsLineItem(parent)
    , m_startItem(startItem)
    , m_endItem(nullptr)
    , m_startSide(startSide)
    , m_endSide(Left)
    , m_endIsAnchor(true)
    , m_endAnchorScenePos(endAnchorScenePos)
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setPen(QPen(m_color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    updatePosition();
}

int ConnectionItem::type() const
{
    return Type;
}

void ConnectionItem::setPolylineMode(bool on, const QPointF& bendPoint)
{
    m_polyline = on;
    m_bend = bendPoint;
    update(); // 触发重绘
}

void ConnectionItem::updatePosition() {
    // 允许一端为锚点
    if (!m_startItem && !m_startIsAnchor) return;
    if (!m_endItem   && !m_endIsAnchor)   return;

    QPointF startPoint;
    if (m_startIsAnchor) {
        startPoint = m_startAnchorScenePos;
    } else {
        QPointF localStart = (m_startSide == Right)
        ? m_startItem->rightConnectionPoint()
        : m_startItem->leftConnectionPoint();
        startPoint = m_startItem->mapToScene(localStart);
    }

    QPointF endPoint;
    if (m_endIsAnchor) {
        endPoint = m_endAnchorScenePos;
    } else {
        QPointF localEnd = (m_endSide == Right)
        ? m_endItem->rightConnectionPoint()
        : m_endItem->leftConnectionPoint();
        endPoint = m_endItem->mapToScene(localEnd);
    }

    setLine(QLineF(startPoint, endPoint));
}

PlcElement *ConnectionItem::startItem() const
{
    return m_startItem;
}

PlcElement *ConnectionItem::endItem() const
{
    return m_endItem;
}

ConnectionItem::Side ConnectionItem::endSide() const
{
    return m_endSide;
}

ConnectionItem::Side ConnectionItem::startSide() const
{
    return m_startSide;
}

bool ConnectionItem::startIsAnchor()
{
    return m_startIsAnchor;
}

bool ConnectionItem::endIsAnchor()
{
    return m_endIsAnchor;
}

void ConnectionItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
    Q_UNUSED(option);
    Q_UNUSED(widget);

    // 如果两端都是元素，保持原来的碰撞过滤
    if (!m_startIsAnchor && !m_endIsAnchor) {
        if (m_startItem && m_endItem && m_startItem->collidesWithItem(m_endItem)) return;
    }

    painter->setPen(pen());

    const QPointF p1 = line().p1();
    const QPointF p2 = line().p2();

    if (m_polyline) {
        // L 形：p1 -> m_bend -> p2
        painter->drawLine(QLineF(p1, m_bend));
        painter->drawLine(QLineF(m_bend, p2));
    } else {
        painter->drawLine(line());
    }

    if (isSelected()) {
        painter->setPen(QPen(Qt::red, 1, Qt::DashLine));
        if (m_polyline) {
            painter->drawLine(QLineF(p1, m_bend));
            painter->drawLine(QLineF(m_bend, p2));
        } else {
            painter->drawLine(line());
        }
    }
}

QPainterPath ConnectionItem::shape() const
{
    // 构造“几何路径”：直线或折线（p1 -> bend -> p2）
    const QPointF p1 = line().p1();
    const QPointF p2 = line().p2();

    QPainterPath path;
    path.moveTo(p1);
    if (m_polyline) {
        path.lineTo(m_bend);
        path.lineTo(p2);
    } else {
        path.lineTo(p2);
    }

    // 用描边器把可点选的“粗度”做出来
    QPainterPathStroker stroker;
    qreal w = pen().widthF();                 // 画笔宽度
    if (w <= 0) w = 1.0;                      // cosmetic pen
    // 适当放大可点击范围，避免细线难点中（比如 6~8px）
    stroker.setWidth(std::max<qreal>(w, 8.0));
    stroker.setCapStyle(pen().capStyle());
    stroker.setJoinStyle(pen().joinStyle());

    return stroker.createStroke(path);
}

QRectF ConnectionItem::boundingRect() const
{
    // 用 shape 的包围盒，保证第二段也在包围框内
    return shape().controlPointRect();
}
